package 定时器;

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.concurrent.PriorityBlockingQueue;

public class 实现定时器 {


    //使用 Timer 这个带 优先级版本的阻塞队列来组织任务
    //写内部类，是为了避免和标准库中的Timer冲突
    static class Timer  {
        private PriorityBlockingQueue<Task> queue=new PriorityBlockingQueue<>();
        private Object locker =new Object();

        public void schedule(Runnable commmand,long delay) {
            Task task=new Task(commmand,delay);
            queue.put(task);

            synchronized (locker) {
                locker.notify();//每次有新的任务入队列时尝试唤醒等待的扫描线程，保证新的任务不会错过
            }
        }
        public Timer() {
            //创建一个扫描线程，这个扫描线程来判定 当前任务是否已经时间能执行？？？

            Thread t=new Thread() {
                @Override
                public void run() {
                    while (true) {
                        //取出队列的首元素,判定该元素是否到该执行的时间
                        try {
                            Task task=queue.take();
                            long curTime=System.currentTimeMillis();//当前时间
                            //判断当前任务的时间是否大于当前时间
                            if (task.time > curTime) {
                                //还没到 执行时间,再放回队列中
                                queue.put(task);
                                //执行时间还没到，避免 “忙等”的问题，进行wait,等待时间为time和curTime的时间差
                                synchronized (locker) {
                                    locker.wait(task.time-curTime);
                                }

                            }else {
                                //到 执行时间,调用run()
                                task.run();
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();

                            //如果出现 interrupt方法就能退出线程
                            break;
                        }
                    }
                }
            };
            t.start();
        }

    }


    //使用 Task 来描述任务
    static class Task implements Comparable<Task>{
        //包含 Runnable和时间
        private Runnable command;//command 代表任务是什么
        private long time;//time 代表任务什么时候执行的时间，使用毫秒级的时间戳


        //构造方法中约定 参数time 是一个时间差(接近3000)
        //希望 this.time 保存一个绝对的时间(毫秒级的时间戳)
        public Task(Runnable command, long time) {
            this.command = command;
            this.time = System.currentTimeMillis()+time;
        }

        public void run() {
            command.run();
        }

        @Override
        public int compareTo(Task o) {
            return (int)(this.time-o.time);//建立小堆
        }
    }

    public static void main(String[] args) {
        System.out.println("程序启动！");
        Timer timer=new Timer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello");
            }
        },3000);

        Timer timer2=new Timer();
        timer2.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("dddd");
            }
        },2000);

        Timer timer3=new Timer();
        timer3.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("ssss");
            }
        },1000);
    }
}
